/*   The MIT License
 *   
 *   Carina Common
 *   Copyright (c) 2010-2012 Zdravko Velinov
 *   
 *   Permission is hereby granted, free of charge, to any person obtaining a copy
 *   of this software and associated documentation files (the "Software"), to deal
 *   in the Software without restriction, including without limitation the rights
 *   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *   copies of the Software, and to permit persons to whom the Software is
 *   furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 *   THE SOFTWARE.
 */

#ifndef _CES_FILE_FORMAT_HH_
#define _CES_FILE_FORMAT_HH_

#include "carina/common/types.hh"

//! Represents a 2-dimensional vector in CES format.
union vec2_t
{
    //! Represents the actual vector as a structure containing separate coordinate components.
    struct ind
    {
        float x, //!< x-coordinate component.
              y; //!< y-coordinate component.
    };
    //! The 2-dimensional vector represented in Cartesian coordinate system.
    ind coordinate;
    //! The 2-dimensional vector represented as an array.
    float elem[2];
};

//! Represents a 3-dimensional vector in CES format.
union vec3_t
{
    //! Represents the actual vector as a structure containing separate coordinate components.
    struct ind
    {
        float x, //!< x-coordinate component.
              y, //!< y-coordinate component.
              z; //!< z-coordinate component.
    };
    //! The 3-dimensional vector represented in Cartesian coordinate system.
    ind coordinate;
    //! The 3-dimensional vector represented as an array.
    float elem[3];
};

//! Represents a 4-dimensional vector in CES format.
union vec4_t
{
    //! Represents the actual vector as a structure containing separate coordinate components.
    struct ind
    {
        float x, //!< x-coordinate component.
              y, //!< y-coordinate component.
              z, //!< z-coordinate component.
              w; //!< w-coordinate component.
    };
    //! The 4-dimensional vector represented in Cartesian coordinate system.
    ind coordinate;
    //! The 4-dimensional vector represented as an array.
    float elem[4];
};

//! Represents a quaternion in CES format.
union quat_t
{
    //! Represents the actual quaternion as a structure containing separate coordinate components.
    struct ind
    {
        float x, //!< x-coordinate component.
              y, //!< y-coordinate component.
              z, //!< z-coordinate component.
              w; //!< w-coordinate component.
    };
    //! The quaternion represented in 4-dimensional space.
    ind coordinate;
    //! Represents the actual quaternion as comprised of vector and scalar components.
    struct comp
    {
        vec3_t v; //! vector component of the quaternion.
        float s;  //! scalar component of the quaternion.
    };
    //! The quaternion represented as comprised of vector and scalar components.
    ind component;
    //! The quaternion represented as an array.
    float elem[4];
};

//! Represents a dual quaternion in CES format.
struct dquat_t
{
    //! The real and dual part of the dual quaternion represented as an array of two quaternions.
    quat_t quat[2];
};

//! Represents a 3x3 matrix in CES format.
struct mat3_t
{
    //! The components of the matrix represented as an 2-dimensional array.
    float elem[3][3];
};

//! Represents a 4x4 matrix in CES format.
struct mat4_t
{
    //! The components of the matrix represented as an 2-dimensional array.
    float elem[4][4];
};

//! Represents a filename in CES format.
struct filename_t
{
    //! The filename represented as a fixed-length string.
    char name[256];
};

//! Represents a fixed-length string in CES format.
struct fixed_string_t
{
    //! The string represented as a fixed-length string.
    char str[256];
};

//! The magic number used for recognizing CES files.
const uint32 ces_magic_number = 0xCE5;

//! The current major version of the CES file format.
const uint32 ces_major_version = 0;

//! The current minor version of the CES file format.
const uint32 ces_minor_version = 1;

//! A 2-dimensional vector comprised of zeros.
const vec2_t vec2_zero = {{ 0.0f, 0.0f }};

//! A 3-dimensional vector comprised of zeros.
const vec3_t vec3_zero = {{ 0.0f, 0.0f, 0.0f }};

//! A 4-dimensional vector comprised of zeros.
const vec4_t vec4_zero = {{ 0.0f, 0.0f, 0.0f, 0.0f }};

//! An identity dual quaternion.
const float q_identity_transform[2][4] = { { 0.0f, 0.0f, 0.0f, 1.0f },
                                           { 0.0f, 0.0f, 0.0f, 0.0f } };
//! An identity 4x4 matrix.
const float mat4_identity[4][4] = { { 1.0f, 0.0f, 0.0f, 0.0f },
                                    { 0.0f, 1.0f, 0.0f, 0.0f },
                                    { 0.0f, 0.0f, 1.0f, 0.0f },
                                    { 0.0f, 0.0f, 0.0f, 1.0f } };

//! The header of each CES file.
struct CESHeader
{
    //! The magic number used for recognizing the file as a CES file.
    uint32 magic_number;

    //! The major version of the data inside the file.
    uint16 major_version;

    //! The minor version of the data inside the file.
    uint16 minor_version;
};

//! The data type used for representing indices.
typedef uint32 indice_t;

struct CESNodeHeader
{
    uint32      children;
};

struct CESAttributeContainerHeader
{
    uint32      attributes;
};

struct CESSectionHeader
{
    uint32      count;
};

typedef CESSectionHeader CESGeometrySectionHeader;

struct CESMeshReferenceHeader
{
    uint8       is_in_place;
    char        name[256];
};

struct CESMeshHeader
{
    indice_t    indices;
    uint32      vertex_data;
    uint32      submeshes;
    uint8       is_skinned;
};

struct CESSubmeshHeader
{
    uint32      begin_index;
    uint32      indices;
    char        material[256];
};

enum CESVarType
{
    CES_UNKNOWN,
    CES_ARRAY,
    CES_FLOAT,
    CES_INT,
    CES_SHORT,
    CES_BYTE,
    CES_UINT,
    CES_USHORT,
    CES_UBYTE,
    CES_VECTOR2,
    CES_VECTOR3,
    CES_VECTOR4,
    CES_QUATERNION,
    CES_DUAL_QUATERNION,
    CES_MATRIX3,
    CES_MATRIX4,
    CES_FILENAME,
    CES_FIXED_STRING
};

struct CESAttributeHeader
{
    char        name[256];
    uint32      type;
};

struct CESArrayAttributeHeader
{
    uint32      size;
    uint32      type;
};

struct CESPointData
{
    vec3_t position;
    vec3_t normal;
    vec2_t texcoord;
};

const size_t ces_max_inf_bones=4;
const size_t ces_max_skel_bones=50;

struct CESSkinData
{
    float boneid[ces_max_inf_bones];
    float weight[ces_max_inf_bones];
};

struct CESStaticData
{
    CESPointData point;
};

struct CESSkinnedData
{
    CESPointData point;
    CESSkinData  skin;
};

const size_t ces_static_size_float = sizeof(CESStaticData)/sizeof(float);
const size_t ces_skinned_size_float = sizeof(CESSkinnedData)/sizeof(float);
const size_t ces_skin_size_float = sizeof(CESSkinData)/sizeof(float);

typedef size_t bone_child_t;

struct CESSkeletonHeader
{
    size_t       bone_count;
    size_t       node_count; // bones and additional transform nodes
    bone_child_t root_bone;
};

struct CESBoneHeader
{
    dquat_t q_transform;
    dquat_t q_inv_transform;
    size_t  children_count;
};

typedef CESSectionHeader CESAnimationSectionHeader;

struct CESAnimationHeader
{
    char    name[256];
    uint32  keyframes;
};

struct CESBoneAnimHeader
{
    dquat_t q_transform;
};

typedef float time_seconds;

typedef CESSectionHeader CESEntitySectionHeader;

typedef CESSectionHeader CESGlobalLightSectionHeader;

///////////////////
// CEM subformat //
///////////////////
typedef CESHeader CEMHeader;

const uint32 cem_magic_number = 0xCE111;
const uint32 cem_major_version = ces_major_version;
const uint32 cem_minor_version = ces_minor_version;

typedef CESMeshHeader CEMMeshHeader;

#endif /* _CES_FILE_FORMAT_HH_ */
